/* Copyright (c) 2009-2010, Sean A.O. Harney <sharney3@gmail.com> */

#include "omf.h"


/*
 * pass list_head = NULL for new list). 
 */
void llist_prepend(void *element, LLIST_P * list_head)
{
    LLIST_P temp = checked_malloc(sizeof(struct st_llist));
    temp->element = element;
    temp->next = *list_head;
    *list_head = temp;
}

/*
 * pass *list_head = NULL for new list). 
 * NOTE: not as efficient as llist_prepend().
 */
void llist_append(void *element, LLIST_P * list_head)
{
    LLIST_P walker;
    LLIST_P temp = checked_malloc(sizeof(struct st_llist));
    temp->element = element;
    temp->next = NULL;

    if (*list_head == NULL)	/* new list */
      {
	  *list_head = temp;
	  return;
      }

    /* existing list */
    walker = *list_head;
    while (walker->next != NULL)
	walker = walker->next;

    /* walker is now at list tail cell => walker->next is NULL */
    walker->next = temp;	/* attach new cell to tail of list */
}


// if used, cell size must be set properly or known by callee 
LLIST_P llist_get_at_index(LLIST_P list_head, unsigned int index)
{
    LLIST_P walker;
    unsigned int ind;

    for (walker = list_head, ind = 0; walker != NULL;
	 walker = walker->next, ind++)
      {
	  if (ind == index)
	    {
		return walker;
	    }
      }
    return NULL;
}

size_t llist_size(LLIST_P list_head)
{
    LLIST_P walker;
    size_t size;

    for (walker = list_head, size = 0; walker != NULL;
	 walker = walker->next)
	size++;

    return size;
}


//remove first occurance, or returns false if no occurances
bool llist_int_remove(int value, LLIST_P * list_head, bool free_element)
{
    LLIST_P walker;
    int val;

    if (*list_head == NULL)
	return false;		/* the empty list doesn't contain it */


/* if first element is it, remove it */
    val = *((int *) (*list_head)->element);
    if (val == value)
      {
	  *list_head = (*list_head)->next;
	  return true;
      }

    for (walker = *list_head; walker != NULL && walker->next != NULL;
	 walker = walker->next)
      {
	  val = *((int *) walker->next->element);
	  if (val == value)
	    {
		if (free_element == true)
		    free(walker->next->element);
		free(walker->next);
		walker->next = walker->next->next;	//will be NULL if last element
		return true;	/* on first match */
	    }
      }

    return false;		// not found

}



// do any llist elements point to an int with this value?
bool llist_int_contains(int value, LLIST_P list_head)
{
    LLIST_P walker;

    if (list_head == NULL)
	return false;		/* the empty list doesn't contain it */

    for (walker = list_head; walker != NULL; walker = walker->next)
      {
	  int val = *((int *) walker->element);
	  if (val == value)
	      return true;	/* on first match */
      }
    return false;
}



/* print an LLIST_P of ints */
void llist_int_print(FILE * fp, LLIST_P list_head)
{
    LLIST_P walker;

    if (list_head != NULL)
      {
	  for (walker = list_head; walker != NULL; walker = walker->next)
	    {
		int val = *((int *) walker->element);
		fprintf(fp, "%d%s", val,
			(walker->next != NULL) ? " , " : "\n");
	    }
    } else
	fprintf(fp, "List is empty.\n");

    fflush(fp);
}


//return -1 if not found, else index into list_head of first occurance
int llist_str_index(char *value, LLIST_P list_head)
{
    LLIST_P walker;
    int index;

    if (list_head == NULL)
	return -1;		/* the empty list doesn't contain it */

    for (walker = list_head, index = 0; walker != NULL;
	 walker = walker->next, index++)
      {
	  char *val = walker->element;
	  if (!strcmp(val, value))
	      return index;	/* on first match */
      }
    return -1;
}
